/*
 * CreepTransactionServer - threaded remoting server for scores and recordings
 *
 * Copyright 2007 James W. Hofmann
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

import neko.Sys;
import neko.net.Socket;
import neko.vm.Thread;
import haxe.Unserializer;
import neko.io.File;
import neko.FileSystem;
import CreepData;
	
class CreepTransactionServer
{

	public static var curversion : Int = 2;
	public static var curday : Int;
	public static var curgame : Int;
	
	public static var s : Socket; 
	
	public static function getnum() : Int
	{
		var now = Date.now();
		if (now.getDay()!=curday)
		{
			var lockfornewday = new neko.vm.Lock();
			curday = now.getDay();
			curgame = GenNum.todaysgame(Date.now());
			writecurrentgame();
			lockfornewday.release();
		}
		return curgame;
	}
    public static function dbconnect()
	{        
        // initialize the connection
        var useMysql = true;
		var cnx : neko.db.Connection;
        if( !useMysql )
            cnx = neko.db.Sqlite.open("mydatabase_file.db");
        else {
            cnx = neko.db.Mysql.connect({ 
                host : CreepData.databaselocale,
                port : 3306,
                database : CreepData.databasename,
                user : CreepData.databaselogin,
                pass : CreepData.databasepass,
                socket : null
            });
        }
 
        neko.db.Manager.cnx = cnx;
        neko.db.Manager.initialize();
    }
	
    public static function db_initTable() 
	{
		CreepData.initTable(neko.db.Manager.cnx);
    }

	public static function db_addScore(serialized : String)
	{
		CreepData.addScore(serialized, getnum());
	}

	public static var clients = new List<ClientData>();

	static function initClientApi( scnx : haxe.remoting.SocketConnection, server : neko.net.RemotingServer ) 
	{
		trace("Client connected");
		var c = new ClientData(scnx);
		server.addObject("api",c);
	}

		static function onClientDisconnected( scnx ) {
		trace("Client disconnected");
	}

	public static function gennums()
	{
		///// to set up all the game numbers on the database for hs frontend
		trace("ADDING ALL GAME NUMBERS TO MYSQL");
		for (n in 0...GenNum.data.length)
		{
			neko.db.Manager.cnx.request(
				"INSERT INTO GameNums
				SET gamenum="+Std.string(GenNum.data[n])
				);
		}
		trace("GAMES ARE ADDED!");
	
	}
	
	static function main() 
	{

		CreepData.loadDbInfo();
		GenNum.loadcache();
		dbconnect();

		var curdate = Date.now();
		curday = curdate.getDay();
		curgame = GenNum.todaysgame(Date.now());
		writecurrentgame();
		
		//gennums(); // only do this following a catastrophic failure
		
		var s = new neko.net.ThreadRemotingServer();
		s.initClientApi = initClientApi;
		s.clientDisconnected = onClientDisconnected;
		trace("Starting server...");
		s.run("spacecreeps.com",10074);
	}

	public static function writecurrentgame()
	{
		neko.db.Manager.cnx.request(
			"UPDATE Settings
			SET value="+Std.string(curgame)+
			" WHERE name='curgame'"
			);
		trace("updated today's game.");
	}
	
}

// define a typed remoting API
class ClientApiImpl extends haxe.remoting.AsyncProxy<ClientApi> {
}

// our client class
class ClientData implements ServerApi {

	var api : ClientApiImpl;
	var recording : String;
	var bufferstart : Int;
	var bufferend : Int;
	
	public function new( scnx : haxe.remoting.SocketConnection ) {
		api = new ClientApiImpl(scnx.Client.inst);
		(cast scnx).__private = this;
	}

	public function uploadgame( recording : String, lastpart : Bool )
	{
		if (this.recording==null)
		{
			this.recording = recording;
		}
		else
		{
			this.recording += recording;
		}
		if (lastpart)
		{
			CreepTransactionServer.db_addScore(this.recording);
			api.scoreissaved();
		}
		else
		{
			api.continuedownload();
		}
	}

	public function continuedownload()
	{
		if (bufferend<this.recording.length)
		{
			bufferend+=3000;
			api.uploadgame(this.recording.substr(bufferstart,3000),false);
			bufferstart+=3000;
		}
		else
		{
			api.uploadgame(this.recording.substr(bufferstart),true);		
		}
	}
	
	public function downloadgame( gamenumber : Int )
	{
		trace(["sending game ",gamenumber]);
		var results =
		neko.db.Manager.cnx.request(
		"SELECT recordingdata FROM CreepData WHERE gamenumber!="+CreepTransactionServer.curgame+" AND id = "+Std.string(gamenumber)
		);
		if (results.length>0)
		{
			this.recording = results.getResult(0);
			bufferstart = 0;
			bufferend = 0;
			neko.db.Manager.cnx.request(
			"UPDATE CreepData
			SET downloads=downloads+1
			WHERE id="+Std.string(gamenumber)
			);
			continuedownload();
		}
		else
		{
			api.nosuchrecording();
		}
	}

	public function downloadnumber( )
	{
		api.sendnumber(CreepTransactionServer.getnum());
	}
	
	public static function ofConnection( scnx : haxe.remoting.SocketConnection ) : ClientData 
	{
		return (cast scnx).__private;
	}

}
